package com.beep.erp.http;

import android.content.Context;

import com.beep.erp.AppContext;
import com.beep.erp.BuildConfig;
import com.beep.erp.Constants;
import com.beep.erp.common.base.BaseBean;
import com.beep.erp.common.bean.ResultBean;
import com.beep.erp.common.utils.AppUtils;
import com.beep.erp.common.utils.FileUtils;
import com.beep.erp.common.utils.NetUtils;
import com.beep.erp.common.utils.SPUtils;
import com.beep.erp.common.utils.SignUtil;
import com.beep.erp.common.utils.TimeUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import okio.BufferedSource;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

import static com.beep.erp.AppContext._context;


/**
 * FileName: HttpRetrofit
 * description:网络请求服务
 * Author: Jolly
 * Date: 2018/9/22
 */
public class HttpRetrofit {
    public static final int DEFAULT_TIMEOUT = 60;

    public Retrofit retrofit;
    public HttpService apiService;

    //在访问HttpMethods时创建单例
    private static class SingletonHolder {
        private static final HttpRetrofit INSTANCE = new HttpRetrofit();
    }

    //获取单例
    public static HttpRetrofit getInstance() {
        return SingletonHolder.INSTANCE;
    }

    //构造方法私有
    private HttpRetrofit() {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create();
        retrofit = new Retrofit.Builder()
                .baseUrl(Constants.API_URL)
                .client(getOkHttpClient())
                .addConverterFactory(GsonConverterFactory.create(gson)) //  添加数据解析ConverterFactory
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //添加RxJava
                .build();
        apiService = retrofit.create(HttpService.class);
    }


    /**
     * 配置OKHTTP
     * l
     *
     * @return OkHttpClient
     */
    public OkHttpClient getOkHttpClient() {
        File httpCacheDirectory = new File(FileUtils.getCacheDir(AppContext.getInstance()), "OkHttpCache"); //设置缓存
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();//拦截器
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();  //定制OkHttp
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); //设置连接超时
        httpClientBuilder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);   //设置写入超时
        httpClientBuilder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);    //设置读取超时
        httpClientBuilder.cache(new Cache(httpCacheDirectory, 10 * 1024 * 1024));//设置缓存目录和10M缓存
        String hosts[] = {Constants.API_URL};
        httpClientBuilder.hostnameVerifier((hostname, session) -> {
            return true;
/*                HostnameVerifier hv =
                    HttpsURLConnection.getDefaultHostnameVerifier();
            return hv.verify(Constants.API_URL, session);*/
        });
        /*        httpClientBuilder.hostnameVerifier(getHostnameVerifier(hosts));*/

        if (BuildConfig.DEBUG)
            httpClientBuilder.addInterceptor(interceptor); //添加日志拦截器（该方法也可以设置公共参数，头信息）
        httpClientBuilder.addInterceptor(new CommonInterceptor());
        httpClientBuilder.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
        //httpClientBuilder.retryOnConnectionFailure(true); //错误重连
        return httpClientBuilder.build();
    }

    private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
        for (TrustManager trustManager : trustManagers) {
            if (trustManager instanceof X509TrustManager) {
                return (X509TrustManager) trustManager;
            }
        }
        return null;
    }


    private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
        SPUtils spUtils = new SPUtils(_context, Constants.EXTRA_LOGIN_SP);
        CacheControl.Builder cacheBuilder = new CacheControl.Builder();
        cacheBuilder.maxAge(0, TimeUnit.SECONDS);
        cacheBuilder.maxStale(365, TimeUnit.DAYS);
        CacheControl cacheControl = cacheBuilder.build();

        Request request = chain.request()
                .newBuilder()
                .build();
        if (!NetUtils.isConnected(AppContext.context())) {
            request = request.newBuilder()
                    .cacheControl(cacheControl)
                    .build();
        }
        Response originalResponse = chain.proceed(request);
        if (NetUtils.isConnected(AppContext.context())) {
            int maxAge = 0; // 从缓存中读取
            return originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public ,max-age=" + maxAge)
                    .build();
        } else {
            int maxStale = 60 * 60 * 24 * 28; //缓存4周
            return originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .build();
        }

    };

    public class CommonInterceptor implements Interceptor {

        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request oldRequest = chain.request();
            // 添加新的参数
            HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
                    .newBuilder()
                    .scheme(oldRequest.url().scheme())
                    .host(oldRequest.url().host());

            // 新的请求
            Request newRequest;
            if (AppContext.getInstance().isLogin()) {
                newRequest = oldRequest.newBuilder()
                        .method(oldRequest.method(), oldRequest.body())
                        .url(authorizedUrlBuilder.build())
                        .addHeader(Constants.KEY_VERSION, AppUtils.VERSION)
                        .addHeader(Constants.KEY_APP_TYPE, "Android")
                        .addHeader(Constants.KEY_OS, AppUtils.OS)
                        .addHeader(Constants.USER_NAME, new SPUtils(_context, Constants.EXTRA_LOGIN_SP).getString(Constants.USER_NAME))
                        .build();
            } else {
                newRequest = oldRequest.newBuilder()
                        .method(oldRequest.method(), oldRequest.body())
                        .url(authorizedUrlBuilder.build())
                        .addHeader(Constants.KEY_VERSION, AppUtils.VERSION)
                        .addHeader(Constants.KEY_APP_TYPE, "Android")
                        .addHeader(Constants.KEY_OS, AppUtils.OS)
                        .build();
            }
            return chain.proceed(newRequest);
        }
    }

    /**
     * 绑定证书
     *
     * @param context      上下文
     * @param certificates 证书源
     * @return
     */
    private static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
        if (context == null) {
            throw new NullPointerException("context == null");
        }

        try {
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            for (int i = 0; i < certificates.length; i++) {
                InputStream certificate = context.getResources().openRawResource(certificates[i]);
                keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));
                if (certificate != null) {
                    certificate.close();
                }
            }
            SSLContext sslContext = SSLContext.getInstance("SSL");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            //sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            sslContext.init(null, trustAllCerts, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException | KeyManagementException e) {
            throw new AssertionError(e);
        }
    }

    /**
     * @param hostUrls
     * @return
     */
    private static HostnameVerifier getHostnameVerifier(final String[] hostUrls) {
        return (hostname, session) -> {
            boolean ret = false;
            for (String host : hostUrls) {
                if (host.equalsIgnoreCase(hostname)) {
                    ret = true;
                }
            }
            return ret;
        };
    }

    /**
     * 线程切换操作
     *
     * @param <T>
     * @return
     */
    public static <T> Observable.Transformer<T, T> toSubscribe() {
        return tObservable -> tObservable.subscribeOn(Schedulers.io())//访问网络切换异步线程
                .unsubscribeOn(Schedulers.io())//销毁访问网络切换异步线程
                .observeOn(AndroidSchedulers.mainThread()); //响应结果处理切换成主线程

    }

    /**
     * @param <T>
     * @return
     */
    public static <T extends BaseBean> Observable.Transformer<ResultBean<T>, T> toTransformer() {
        return tObservable ->
                tObservable.map(new HttpResultFunc<>())
                        .subscribeOn(Schedulers.newThread())
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .onErrorResumeNext(new HttpResponseFunc<>());

    }

    public static <T> Observable.Transformer<T, T> toTransformer1() {
        return tObservable ->
                tObservable.subscribeOn(Schedulers.newThread())
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .onErrorResumeNext(new HttpResponseFunc<>());

    }

    private static class HttpResponseFunc<T> implements Func1<Throwable, Observable<T>> {
        @Override
        public Observable<T> call(Throwable t) {
            return Observable.error(HttpExceptionHandle.handleException(t));
        }
    }

}